package locadora.model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

/**
 * Classe concreta que representa uma Locadora
 * @author Leonardo Rocha Dias
 * @author Marccelo Augusto Selvaggio
 * @version 9.11-09
 * @see Locadora
 * @since 2009
 */
public class LocadoraImplementacao implements Locadora {

    // TODO devo implementar tratamento nos setters para ficar como os adders(addCliente, addItem) ?
    // TODO devo alugar o item ao adicioná-lo ao cliente ? Não pois é uma lista de interesse
    // TODO devo remover o item da lista do cliente ao alugar   
    // <editor-fold defaultstate="collapsed" desc=" Atributos ">
    //private Map<String, Cliente> clientes;
    private Collection<Cliente> clientes;
    private Collection<ItemLocacao> acervo;
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Construtor ">
    public LocadoraImplementacao() {
        /**
         * Os dados estão literalmente espalhados, mas organizados
         * Interessante quando não importa a ordem e não se quer percorrer
         * a coleção inteira. Deseja-se uma forma de recuperar rapidamente
         * um elemento e que não seja repetido
         */
        this.clientes = new HashSet<Cliente>();
        //this.clientes = new HashMap<String, Cliente>();

        this.acervo = new HashSet<ItemLocacao>();
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" Propriedades ">
    /**
     * Retorna a coleção de clientes
     *
     * @return coleção de clientes
     */
    public Collection<Cliente> getClientes() {
        return clientes;
    }

    /**
     * Define a coleção de clientes
     *
     * @param clientes a nova coleção de clientes
     */
    public void setClientes(Collection<Cliente> clientes) {
        this.clientes = clientes;
    }

    /**
     * Retorna a coleção de itens do acervo
     *
     * @return a coleção de itens do acervo
     */
    public Collection<ItemLocacao> getAcervo() {
        return acervo;
    }

    /**
     * Define a coleção de itens do acervo
     *
     * @param itens a nova coleção de itens do acervo
     */
    public void setAcervo(Collection<ItemLocacao> acervo) {
        this.acervo = acervo;
    }
    // </editor-fold>

    // <editor-fold defaultstate="lapsed" desc=" Métodos da interface ">
    /**
     * Adiciona um novo item, tanto filme quanto jogo, à locadora
     * @param item, o item que será adicionado
     */
    @Override
    public void addItem(ItemLocacao item) {
        if (item != null) {
            if (!this.getAcervo().contains(item)) {
                this.getAcervo().add(item);
            }
        }
    }

    /**
     * Adiciona um novo cliente à locadora
     * @param cliente, o cliente que será adicionado
     * @return verdadeiro se não existir um cliente com mesmo código
     * ou falso caso contrário
     */
    @Override
    public boolean addCliente(Cliente cliente) {
        boolean resultado = false;

        if (cliente != null) {
            if (!this.getClientes().contains(cliente)) {
                //if (! this.clientes.containsKey(cliente)) {
                this.getClientes().add(cliente);
                //this.clientes.put(cliente.getCodigo() ,cliente);
                resultado = true;
            }
        }

        return resultado;
    }

    /**
     * Devolve uma lista a partir de uma coleção
     * @param colecao a ser convertida em uma lista
     * @return uma coleção ordenada, também conhecida como sequência
     */
    private List<ItemLocacao> listar(Collection<ItemLocacao> colecao) {
        List<ItemLocacao> lista = new ArrayList<ItemLocacao>(colecao);
        return lista;
    }

    /**
     * Lista todos os clientes da locadora
     * @return uma coleçao com todos os clientes
     */
    @Override
    public List<Cliente> listarClientes() {
        List lista = new ArrayList(this.getClientes());
        return lista;
    }

    /**
     * Lista todos os itens da locadora
     * @return uma coleçao com todos os itens(filme, jogo) do acervo
     */
    @Override
    public List<ItemLocacao> listarAcervo() {
        return listar(this.getAcervo());
    }

    /**
     * Adiciona um item ao cliente
     * @param item que o cliente deseja alugar
     * @param cliente que o representa
     * @return verdadeiro ou falso
     */
    @Override
    public boolean addItemAoCliente(ItemLocacao item, Cliente cliente) {
        boolean resultado = false;

        Collection itensCliente = null;

        if ((item != null) && (cliente != null)) {
            //if (item.isDisponivel()) {
            itensCliente = cliente.getItensLocacao();
            if (itensCliente.size() <= 10) {
                if (!itensCliente.contains(item)) {
                    itensCliente.add(item);
                    resultado = true;
                }
            }
            //}
        }

        return resultado;
    }

    /**
     * Muda prioridade de um item do cliente
     * @param cliente
     * @param item que terá a prioridade alterada
     * @param novaPrioridade, a nova prioridade do item do cliente
     * @return verdadeiro ou falso
     */
    @Override
    public boolean mudarPrioridadeDeItem(Cliente cliente, ItemLocacao itemLocacao, int novaPrioridade) {
        boolean resultado = false;

        LinkedList<ItemLocacao> itensCliente = null;

        if ((cliente != null) && (itemLocacao != null)) {
            itensCliente = (LinkedList<ItemLocacao>) cliente.getItensLocacao();
            if (itensCliente.contains(itemLocacao)) {
                if ((novaPrioridade >= 0) && (novaPrioridade < itensCliente.size())) {

                    int index = itensCliente.indexOf(itemLocacao);

                    ItemLocacao antigoItem = itensCliente.set(novaPrioridade, itemLocacao);

                    itensCliente.set(index, antigoItem);

                    resultado = true;
                }
            }
        }

        return resultado;
    }

    /**
     * Registra a devolucao do item
     * @param item que será devolvido
     * @return verdadeiro ou falso
     */
    @Override
    public boolean registrarDevolucao(ItemLocacao item) {
        boolean resultado = false;

        if (item != null) {
            if (!item.isDisponivel()) {
                for (Cliente cliente : this.getClientes()) {
                    if (cliente.getItensLocacao().contains(item)) {
                        resultado = item.devolver();
                        break;
                    }
                }
            }
        }

        return resultado;
    }

    /**
     * Aluga item com base no item
     * @param item
     * @return Cliente
     */
    @Override
    public Cliente alugar(ItemLocacao itemLocacao) {

        Cliente resCliente = null;

        if (itemLocacao != null) {
            for (Cliente cliente : this.getClientes()) {
                if (cliente.getItensLocacao().contains(itemLocacao)) {
                    if (itemLocacao.alugar()) {
                        resCliente = cliente;
                        cliente.getItensLocacao().remove(itemLocacao);
                        break;
                    }

                }
            }
        }

        return resCliente;
    }

    /**
     * Aluga item com base no cliente
     * @param cliente
     * @return Item
     */
    @Override
    public ItemLocacao alugar(Cliente cliente) {

        ItemLocacao itemLocacao = null;

        if (cliente != null) {

            itemLocacao = cliente.getItemPrioridade();
            if (itemLocacao.alugar()) {
                cliente.getItensLocacao().remove(itemLocacao);
            }
        }

        return itemLocacao;
    }
    // </editor-fold>

    /**
     * Lista todos os itens disponíveis na locadora, isto é, não alugados
     * @return uma coleçao com todos os itens(filme, jogo) disponíveis do acervo
     */
    public List<ItemLocacao> listarAcervoDisponivel() {
        List lista = new ArrayList(this.getAcervo().size());

        for (ItemLocacao item : this.getAcervo()) {
            if (item.isDisponivel()) {
                lista.add(item);
            }
        }

        return lista;
    }

    /**
     * Lista todos os itens não disponíveis na locadora, isto é, os alugados
     * @return uma coleçao com todos os itens(filme, jogo) não disponíveis do acervo
     */
    public List<ItemLocacao> listarAcervoIndisponivel() {
        List lista = new ArrayList(this.getAcervo().size());

        for (ItemLocacao item : this.getAcervo()) {
            if (! item.isDisponivel()) {
                lista.add(item);
            }
        }

        return lista;
    }

    /**
     * Aluga todos os itens desejados do cliente
     * @param cliente
     */
    public void alugarItens(Cliente cliente) {

        if (cliente != null) {
            for (ItemLocacao itemLocacao : cliente.getItensLocacao()) {
                itemLocacao.alugar();
            }
        }
    }

    /**
     * Devolve todos os itens alugados do cliente
     * @param cliente
     */
    public void devolverItens(Cliente cliente) {

        if (cliente != null) {
            for (ItemLocacao itemLocacao : cliente.getItensLocacao()) {
                itemLocacao.devolver();
            }
        }
    }
}
